/*
 * 上海毕冉信息技术有限公司 版权所有
 */
package cn.ulc.common.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.ulc.common.model.param.FileParam;
import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Date;

/**
 * Aliyun OSS文件上传工具.
 */
public class AliyunOssFileUtil {
    private final static Log log = LogFactory.get();
    private static OSSClient ossClient = new OSSClient(GlobalConfig.ALI_OSS_ENDPOINT, GlobalConfig.ALI_OSS_ACCESS_KEY_ID, GlobalConfig.ALI_OSS_ACCESS_KEY_SECRET);


    /**
     * 上传文件到OSS公共文件.
     * @param file
     * @return OSS Object Name
     */
    public static String uploadPublicFile(File file) {
        try {
            String bucketName = GlobalConfig.ALI_OSS_BUCKET_NAME;
            InputStream content = new FileInputStream(file);
            // 创建上传Object的Metadata
            ObjectMetadata meta = new ObjectMetadata();
            // 必须设置ContentLength
            meta.setContentLength(file.length());

            // 获取文件的mimeType
            String mimeType = FileUtil.getMimeType(file.getPath());
            meta.setContentType(mimeType);

            // 获取文件的扩展名
            String fileExt = FileUtil.extName(file.getName());


            String dateString = DateUtil.format(new Date(), "yyyyMMdd");
            String objectName = "ulcStoreServe/" + dateString + "/" + RandomUtil.randomString(16) + "." + fileExt;

            // 上传Object.
            PutObjectResult result = ossClient.putObject(bucketName, objectName, content, meta);

            // 打印ETag
            Console.log("LOG01730: upload common {} ,  result etag:{}"  ,file.getName() , result.getETag());
            Console.log("LOG01731: upload common cdnUrlPrefix objectName:{}"  ,objectName);

            BufferedImage sourceImg = ImageIO.read(new FileInputStream(file));
            Integer imgWidth = sourceImg.getWidth();
            // 判断宽度是否大于 size  如果大于 则返回 size 宽度。 否则 返回原宽度
            return GlobalConfig.ASSETS_BASE_URL + "/" + objectName;
        } catch (IOException e) {
//            Logger.warn(e, "LOG01750: upload common to OSS failed!");
            Console.error(e,"LOG01750: upload common to OSS failed!");
            return null;
        }
    }


    /**
     * 上传文件到OSS公共文件.
     * @param file
     * @return OSS Object Name
     */
    public static String uploadPublicFile(File file , Integer size) {
        try {
            String bucketName = GlobalConfig.ALI_OSS_BUCKET_NAME;
            InputStream content = new FileInputStream(file);
            // 创建上传Object的Metadata
            ObjectMetadata meta = new ObjectMetadata();
            // 必须设置ContentLength
            meta.setContentLength(file.length());

            String mimeType =  FileUtil.getMimeType(file.getPath());
            meta.setContentType(mimeType);

            String fileExt = FileUtil.extName(file.getName());


            String dateString = DateUtil.format(new Date(), "yyyyMMdd");
            String objectName = "ulcStoreServe/" + dateString + "/" + RandomUtil.randomString(16) + "." + fileExt;

            // 上传Object.
            PutObjectResult result = ossClient.putObject(bucketName, objectName, content, meta);

            // 打印ETag
            Console.log("LOG01730: upload common {} ,  result etag:{}"  ,file.getName() , result.getETag());
            Console.log("LOG01731: upload common cdnUrlPrefix objectName:{}"  ,objectName);

            BufferedImage sourceImg = ImageIO.read(new FileInputStream(file));
            Integer imgWidth = sourceImg.getWidth();
            // 判断宽度是否大于 size  如果大于 则返回 size 宽度。 否则 返回原宽度
            if(imgWidth > size) {
                //?x-oss-process=image/resize,w_200
                return GlobalConfig.ASSETS_BASE_URL +"/" + objectName + "?x-oss-process=image/resize,w_"+size;
            } else {
                return GlobalConfig.ASSETS_BASE_URL + "/" + objectName + "?x-oss-process=image/resize,w_"+imgWidth;
            }
        } catch (IOException e) {
            Console.error(e,"LOG01750: upload common to OSS failed!");

            return null;
        }
    }


    /**
     * 上传文件到OSS公共文件.
     * @param file
     * @param projectName  项目的名字. OSS 中存放格式    http;//cdn.ulmsale.net/weixin/20160602/xxxxxxxxxx.jpg
     * @return OSS Object Name
     */
    public static String uploadPublicFile(File file , Integer size , String projectName) {
        try {
            String bucketName = GlobalConfig.ALI_OSS_BUCKET_NAME;
            InputStream content = new FileInputStream(file);
            // 创建上传Object的Metadata
            ObjectMetadata meta = new ObjectMetadata();
            // 必须设置ContentLength
            meta.setContentLength(file.length());

            String mimeType = FileUtil.getMimeType(file.getPath());
            meta.setContentType(mimeType);

            String fileExt = FileUtil.extName(file.getName());


            String dateString = DateUtil.format(new Date(), "yyyyMMdd");
            String objectName = projectName +"/" + dateString + "/" + RandomUtil.randomString(16) + "." + fileExt;

            // 上传Object.
            PutObjectResult result = ossClient.putObject(bucketName, objectName, content, meta);

            // 打印ETag

            Console.log("LOG01730: upload common {} ,  result etag:{}"  ,file.getName() , result.getETag());
            Console.log("LOG01731: upload common cdnUrlPrefix objectName:{}"  ,objectName);

            BufferedImage sourceImg = ImageIO.read(new FileInputStream(file));
            Integer imgWidth = sourceImg.getWidth();

            // 判断宽度是否大于 size  如果大于 则返回 size 宽度。 否则 返回原宽度
            if(imgWidth > size) {
                //?x-oss-process=image/resize,w_200
                return GlobalConfig.ASSETS_BASE_URL +"/" + objectName + "?x-oss-process=image/resize,w_"+size;
            } else {
                return GlobalConfig.ASSETS_BASE_URL + "/" + objectName + "?x-oss-process=image/resize,w_"+imgWidth;
            }

        } catch (IOException e) {
            Console.error(e,"LOG01750: upload common to OSS failed!");

            return null;
        }
    }

    /**
     * 上传文件到OSS公共文件.
     *
     * @param fileName
     * @param fileLength
     * @return OSS Object Name
     */
    public static String uploadPublicFile(InputStream in, String fileName, long fileLength) {
        try {
            String bucketName = GlobalConfig.ALI_OSS_BUCKET_NAME;

            // 创建上传Object的Metadata
            ObjectMetadata meta = new ObjectMetadata();

            // 必须设置ContentLength
            meta.setContentLength(fileLength);

            String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1);
            String dateString = DateUtil.format(new Date(), "yyyyMMdd");
            String objectName = "ulcStoreServe/" + dateString + "/" + RandomUtil.randomString(16) + "." + fileExt;

            // 上传Object.
            PutObjectResult result = ossClient.putObject(bucketName, objectName, in, meta);

            // 打印ETag
            Console.log("LOG01730: upload common {} ,  result etag:{}"  ,fileName , result.getETag());
            Console.log("LOG01731: upload common cdnUrlPrefix objectName:{}"  ,objectName);

            //BufferedImage sourceImg = ImageIO.read(in);
            //Integer imgWidth = sourceImg.getWidth();
            // 判断宽度是否大于 size  如果大于 则返回 size 宽度。 否则 返回原宽度
            return GlobalConfig.ASSETS_BASE_URL + "/" + objectName;
        } catch (Exception e) {
            Console.error(e,"LOG01750: upload common to OSS failed!");

            return null;
        }
    }

    /**
     * 上传文件到OSS公共文件.
     * @param file
     * @param projectName  项目的名字. OSS 中存放格式    http;//cdn.ulmsale.net/weixin/20160602/xxxxxxxxxx.jpg
     * @return OSS Object Name
     */
    public static String uploadFile(File file , String projectName) {
        try {
            String bucketName = GlobalConfig.ALI_OSS_BUCKET_NAME;
            InputStream content = new FileInputStream(file);
            // 创建上传Object的Metadata
            ObjectMetadata meta = new ObjectMetadata();
            // 必须设置ContentLength
            meta.setContentLength(file.length());
            String mimeType = FileUtil.getMimeType(file.getPath());
            meta.setContentType(mimeType);

            String fileExt = FileUtil.extName(file.getName());


            String dateString = DateUtil.format(new Date(), "yyyyMMdd");
            String objectName = projectName +"/" + dateString + "/" + RandomUtil.randomString(16) + "." + fileExt;

            // 上传Object.
            PutObjectResult result = ossClient.putObject(bucketName, objectName, content, meta);

            // 打印ETag

            Console.log("LOG01730: upload common {} ,  result etag:{}"  ,file.getName() , result.getETag());
            Console.log("LOG01731: upload common cdnUrlPrefix objectName:{}"  ,objectName);

            return GlobalConfig.ASSETS_BASE_URL +"/" + objectName;

        } catch (IOException e) {
            Console.error(e,"LOG01750: upload common to OSS failed!");
            return null;
        }
    }

    /**
     * 上传文件到OSS公共文件.
     * @param file
     * @param path 存放路径  mp3/20181223/
     * @return OSS Object Name
     */
    public static String uploadPublicFile(File file , String fileName, String path) {
        try {
            String bucketName = GlobalConfig.ALI_OSS_BUCKET_NAME;
            InputStream content = new FileInputStream(file);
            // 创建上传Object的Metadata
            ObjectMetadata meta = new ObjectMetadata();
            // 必须设置ContentLength
            meta.setContentLength(file.length());

            String mimeType = Files.probeContentType(Paths.get(file.getPath()));
            log.info("mimeType  : %s" , mimeType);
            meta.setContentType(mimeType);
//            String fileExt = FileNameUtil.getExtension(file.getName());
            String fileExt =  file.getName().substring(file.getName().lastIndexOf(".") + 1);
            String dateString = DateUtil.format(new Date(), "yyyyMMdd");
            String objectName = path +dateString + "/" + fileName + "." + fileExt;
            log.info("objectName" , objectName);
            // 上传Object.
            PutObjectResult result = ossClient.putObject(bucketName, objectName, content, meta);
            // 打印ETag
            log.info("LOG01730: upload file " + file.getName() + " result etag:" + result.getETag());
            log.info("LOG01731: upload file cdnUrlPrefix objectName:" + objectName);
            return GlobalConfig.ASSETS_BASE_URL + "/" + objectName;
        } catch (IOException e) {
            log.warn(e, "LOG01750: upload file to OSS failed!");
            return null;
        }
    }

    public static void downFileBase64(HttpServletRequest request, HttpServletResponse response, FileParam param){
        try {
            String fileKey = param.getFileKey();
            ClientConfiguration clientConfiguration = new ClientConfiguration();
            clientConfiguration.setSocketTimeout(300*1000);
            String bucketName = GlobalConfig.ALI_OSS_BUCKET_NAME;

            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            OSSObject ossObject = ossClient.getObject(bucketName, fileKey);
            // 读取文件内容。
            System.out.println("Object content:");

            InputStream inputStream =  ossObject.getObjectContent();

            if(inputStream != null) {
                BufferedInputStream reader = new BufferedInputStream(inputStream);
                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                String agent = (String)request.getHeader("USER-AGENT");
                String downloadFileName = "";
                if(agent != null && agent.toLowerCase().indexOf("firefox") > 0) {
                    downloadFileName = "=?UTF-8?B?" + (new String(Base64.encodeBase64(param.getFileName().getBytes("UTF-8")))) + "?=";
                }else downloadFileName = URLEncoder.encode(param.getFileName(), "utf-8");
                response.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
                response.setContentType("application/octet-stream");
                byte[] car = new byte[1024];
                int L = 0;
                while ((L = reader.read(car)) != -1) {
                    out.write(car, 0, L);
                }
                if (out != null) {
                    out.flush();
                    out.close();
                }
                if (reader != null) {reader.close();

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            ossClient.shutdown();
        }
    }

    public static String getFileBase64(HttpServletRequest request,HttpServletResponse response, FileParam param){
        String result = null;
        try {
            String fileKey = param.getFileKey();
            ClientConfiguration clientConfiguration = new ClientConfiguration();
            clientConfiguration.setSocketTimeout(300*1000);
            String bucketName = GlobalConfig.ALI_OSS_BUCKET_NAME;

            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            OSSObject ossObject = ossClient.getObject(bucketName, fileKey);
            // 读取文件内容。
            System.out.println("Object content:");

            InputStream inputStream =  ossObject.getObjectContent();
            BASE64Encoder base64Encoder = new BASE64Encoder();
            String str = "";
            if(inputStream != null) {
                BufferedInputStream reader = new BufferedInputStream(inputStream);
//                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
//                String agent = (String)request.getHeader("USER-AGENT");
//                String downloadFileName = "";
//                if(agent != null && agent.toLowerCase().indexOf("firefox") > 0) {
//                    downloadFileName = "=?UTF-8?B?" + (new String(Base64.encodeBase64(param.getFileName().getBytes("UTF-8")))) + "?=";
//                }else downloadFileName = URLEncoder.encode(param.getFileName(), "utf-8");
//                response.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
//                response.setContentType("application/octet-stream");
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();

                byte[] car = new byte[1024];
                int L = 0;
                while ((L = reader.read(car)) != -1) {
                    outStream.write(car, 0, L);

                }
                byte [] data = outStream.toByteArray();
                str = base64Encoder.encode(data);

                if (outStream != null) {
//                    out.flush();
                    outStream.close();
                }
                if (reader != null) {reader.close();

                }
            }
            result = "data:"+param.getFileType().getValue()+";base64," + str ;
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            ossClient.shutdown();
        }
        return result;
    }

}
